#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_bt.h"
#include "driver/uart.h"
#include "string.h"
#include "esp_types.h"

#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include "ble_spp_server_demo.h"

#include "driver/periph_ctrl.h"
#include "driver/timer.h"
#include "esp_wifi.h"

#include "nvs_flash.h"
#include "nvs.h"

//add
#include "ble_data_handle.h"
#include "esp_partition.h"
#include "flash.h"
#include "gpio.h"
#include "flash.h"

#define TAG "BLE_DATA_HANDLE"

extern xQueueHandle ble_send_evt_queue;
extern xQueueHandle led_queue;

unsigned char ble_data_buf[BLE_CMD_DATA_MAX_LEN];
unsigned int ble_data_count = 0;

static RTC_DATA_ATTR struct timeval sleep_enter_time;

/*
    函数功能：打印输出接收ble数据
    函数名称：ble_data_log
    输入：typed                 BLE_RX/BLE_TX
    输入：data                  ble数据
    输入：len                   数据长度
*/
void ble_data_log(unsigned char typed, unsigned char *data, unsigned short len)
{
    char *log_str;
    char *log_str2;

    log_str = (char *)malloc(BLE_CMD_DATA_MAX_LEN * 3);

    if (!log_str)
    {
        ESP_LOGI(TAG, "申请打印空间失败\n");
        return;
    }

    switch (typed)
    {
    case BLE_RX:
        ESP_LOGI(TAG, "receive ble data len:%u\n", len);
        break;
    case BLE_TX:
        ESP_LOGI(TAG, "send ble data len:%u\n", len);
        break;
    }

    memset(log_str, 0, BLE_CMD_DATA_MAX_LEN * 3);
    log_str2 = log_str;
    sprintf(log_str, "0x");
    for (int i = 0; i < len; i++)
        sprintf(log_str, "%s%02x ", log_str2, data[i]);
    ESP_LOGI(TAG, "%s\n", log_str);

    free(log_str);
}

/*
    函数功能：接收ble数据
    函数名称：ble_com_get
    输入：data                  ble数据
    输入：len                   数据长度
*/
void ble_com_get(unsigned char *data, unsigned short len)
{
    uint32_t firmwart_len;
    uint32_t firmwart_offset;
    uint32_t firmwart_size;
    uint32_t firmwart_limit;
    uint32_t erase_size;
    uint8_t chack_md5[16];
    uint8_t led_typed[3];
    uint8_t *temp_buf;

    if (len > BLE_CMD_DATA_MAX_LEN)
        return;

    memset(ble_data_buf, 0, sizeof(ble_data_buf));
    memcpy(ble_data_buf, data, len);

    if (ble_data_buf[0] == ((BLE_CMD_PACK_HEAD & 0xFF00) >> 8) && ble_data_buf[1] == ((BLE_CMD_PACK_HEAD & 0x00FF) >> 0))
    {
        ESP_LOGI(TAG, "[free mem=%d;] \n", esp_get_free_heap_size());

        unsigned char sum = 0, cmd_len = data[3];
        for (int i = 0; i < (cmd_len + 4); i++)
            sum += ble_data_buf[i];

        if (sum == ble_data_buf[cmd_len + 4])
        {
            uint8_t ble_sned_data[BLE_CMD_DATA_MAX_LEN];
            memset(ble_sned_data, 0, sizeof(ble_sned_data));

            switch (ble_data_buf[2])
            {
            case BLE_CMD_SEND_FIRMWARE_DATA:
                firmwart_offset = ble_data_buf[4] << 24 | ble_data_buf[5] << 16 | ble_data_buf[6] << 8 | ble_data_buf[7] << 0;
                firmwart_len = ble_data_buf[3] - 4;

                ESP_LOGW(TAG, "固件数据指令\n");
                ESP_LOGW(TAG, "固件数据起始地址：%08X\n", firmwart_offset);
                ESP_LOGW(TAG, "固件数据长度：%u\n", firmwart_len);

                /*
                    写入固件信息
                */
                ESP_ERROR_CHECK(flash_firmwart_write(firmwart_offset, (const void *)(&ble_data_buf[8]), firmwart_len));

                /*
                    读取固件信息
                */
                temp_buf = (uint8_t *)malloc(firmwart_len);
                assert(temp_buf != NULL);

                memset(temp_buf, 0, firmwart_len);
                ESP_ERROR_CHECK(flash_firmwart_read(firmwart_offset, (void *)temp_buf, firmwart_len));

                for (size_t i = 0; i < firmwart_len; i++)
                {
                    if (ble_data_buf[i + 8] != temp_buf[i])
                    {
                        ESP_LOGE(TAG, "固件写入错误\n");
                        free(temp_buf);
                        ble_sned_data[0] = 0;
                        ble_ack(BLE_CMD_SEND_FIRMWARE_DATA, ble_sned_data, 1);
                        break;
                    }
                }

                ESP_LOGW(TAG, "固件写入正确\n");
                free(temp_buf);

                ble_sned_data[0] = 1;
                ble_ack(BLE_CMD_SEND_FIRMWARE_DATA, ble_sned_data, 1);
                break;
            case BLE_CMD_FIRWART_INFO:
                firmwart_size = ble_data_buf[4] << 24 | ble_data_buf[5] << 16 | ble_data_buf[6] << 8 | ble_data_buf[7] << 0;

                ESP_LOGW(TAG, "固件信息\n");
                ESP_LOGW(TAG, "固件长度：%u\n", firmwart_size);
                ESP_LOGW(TAG, "固件MD5: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
                         ble_data_buf[8],
                         ble_data_buf[9],
                         ble_data_buf[10],
                         ble_data_buf[11],
                         ble_data_buf[12],
                         ble_data_buf[13],
                         ble_data_buf[14],
                         ble_data_buf[15],
                         ble_data_buf[16],
                         ble_data_buf[17],
                         ble_data_buf[18],
                         ble_data_buf[19],
                         ble_data_buf[20],
                         ble_data_buf[21],
                         ble_data_buf[22],
                         ble_data_buf[23]);

                firmwart_limit = ble_data_buf[24] << 24 | ble_data_buf[25] << 16 | ble_data_buf[26] << 8 | ble_data_buf[27] << 0;
                ESP_LOGW(TAG, "次数限制：%u\n", firmwart_limit);

                if (firmwart_size > FIRMWART_SIZE)
                {
                    /*
                        固件超出长度
                    */
                    ble_sned_data[0] = 0;
                    ble_ack(BLE_CMD_FIRWART_INFO, ble_sned_data, 1);
                    break;
                }
                /*
                    请求所需擦除页数量
                */
                erase_size = firmwart_size / FLASH_PAGE_SIZE;
                if (firmwart_size % FLASH_PAGE_SIZE)
                    erase_size++;

                /*
                    擦除固件数据
                */
                ESP_ERROR_CHECK(flash_firmwart_erase(erase_size * FLASH_PAGE_SIZE));

                /*
                    擦除固件信息
                */
                ESP_ERROR_CHECK(flash_firmwart_info_erase());
                ESP_LOGW(TAG, "原固件信息清空完毕\n");

                /*
                    记录固件信息
                */
                ESP_ERROR_CHECK(flash_firmwart_info_write(0, &ble_data_buf[4], 24));
                ESP_LOGW(TAG, "已记录为新固件信息\n");

                /*
                    次数限制写入到nvs
                */
                set_number_limit(firmwart_limit);
                uint32_t get_firmwart_limit;
                get_number_limit(&get_firmwart_limit);
                if(get_firmwart_limit == firmwart_limit)
                    ESP_LOGW(TAG, "次数限制信息写入nvs成功，次数：%u\n",firmwart_limit);
                else
                    ESP_LOGW(TAG, "次数限制信息写入nvs失败\n");
                
                vTaskDelay(1000 / portTICK_PERIOD_MS);
                ble_sned_data[0] = 1;
                ble_ack(BLE_CMD_FIRWART_INFO, ble_sned_data, 1);
                break;
            case BLE_CMD_FIRWART_SUM_RET:
                if (flash_chack_sum(chack_md5) == ESP_OK)
                {
                    led_typed[0] = LED_EVENT_TWINKLE;
                    led_typed[1] = LED_2;
                    led_typed[2] = 0;
                    xQueueSend(led_queue, led_typed, NULL);

                    ble_sned_data[0] = 1;
                    memcpy(&ble_sned_data[1], chack_md5, 16);
                    ble_ack(BLE_CMD_FIRWART_SUM_RET, ble_sned_data, 17);
                    break;
                }
                else
                {
                    ble_sned_data[0] = 0;
                    ble_sned_data[1] = 0;
                    ble_sned_data[2] = 0;
                    ble_ack(BLE_CMD_FIRWART_SUM_RET, ble_sned_data, 3);
                    break;
                }
                break;
            default:
                ESP_LOGI(TAG, "未知命令\n");
                break;
            }
        }

        ESP_LOGI(TAG, "[free mem=%d;] \n", esp_get_free_heap_size());
    }
}

/*
    函数功能：应答ble命令
    函数名称：ble_ack
    输入：cmd                   指令码
    输入：data                  数据
    输入：len                   数据长度
*/
void ble_ack(unsigned char cmd, unsigned char *data, unsigned char len)
{
    ble_data_t ble_sned_data;
    memset(ble_sned_data.data, 0, sizeof(ble_sned_data.data));

    ble_sned_data.data[0] = (BLE_CMD_PACK_HEAD & 0xFF00) >> 8;
    ble_sned_data.data[1] = (BLE_CMD_PACK_HEAD & 0x00FF) >> 0;
    ble_sned_data.data[2] = cmd;
    ble_sned_data.data[3] = len;
    memcpy(&ble_sned_data.data[4], data, len);

    for (int i = 0; i < (len + 4); i++)
        ble_sned_data.data[len + 4] += ble_sned_data.data[i];
    ble_sned_data.len = ble_sned_data.data[3] + 5;

    xQueueSend(ble_send_evt_queue, &ble_sned_data, 100 / portMAX_DELAY);
}
